//
// Created by mio on 25-4-10.
//

#ifndef CHANNEL_H
#define CHANNEL_H

#include <functional>
#include <memory>

enum EventType
{
    EVENT_NONE  = 0,    // 00000 (二进制) - 无事件
    EVENT_IN    = 1,    // 00001 - 可读事件 (数据到达)
    EVENT_PRI   = 2,    // 00010 - 优先数据 (带外数据)
    EVENT_OUT   = 4,    // 00100 - 可写事件 (发送缓冲区未满)
    EVENT_ERR   = 8,    // 01000 - 错误事件
    EVENT_HUP   = 16,   // 10000 - 对端关闭连接 (Hang Up)
    EVENT_RDHUP = 8192  //       - 对端关闭写(RDHUP)
};

class Channel {
public:
    using EventCallback = std::function<void()>;
    Channel(int sockfd) : sockfd_(sockfd), events_(EVENT_NONE) {}
    ~Channel(){}

    inline void SetReadCallback(const EventCallback& cb) { read_callback_ = cb; }
    inline void SetWriteCallback(const EventCallback& cb) { write_callback_ = cb; }
    inline void SetCloseCallback(const EventCallback& cb) { close_callback_ = cb; }
    inline void SetErrorCallback(const EventCallback& cb) { error_callback_ = cb; }
    inline void SetEvents(int events) { events_ = events; }

    inline int GetSocket() { return sockfd_; }
    inline int GetEvents() { return events_; }

    /* 按位或赋值 |=:  将 events_ 变量中代表 EVENT_IN 的那一位设置为 1，而不影响其他位*/
    inline void EnableRead() { events_ |= EVENT_IN; }
    inline void EnableWrite() { events_ |= EVENT_OUT; }
    /* 按位与非赋值 &= ~: 将 events_ 变量中代表 EVENT_IN 的那一位设置为 0 */
    inline void DisableRead() { events_ &= ~EVENT_IN; }
    inline void DisableWrite() { events_ &= ~EVENT_OUT; }

    inline bool IsNoneEvent() const { return events_ == EVENT_NONE; }
    /* 使用按位与 & 检查 events_ 中 EVENT_IN 对应的比特位是否为 1。如果是，则返回 true，表示当前 Channel 正在关心可读事件 */
    inline bool IsReadEvent() const { return (events_ & EVENT_IN) != 0; }
    inline bool IsWriteEvent() const { return (events_ & EVENT_OUT) != 0; }

    void HandleEvent(int events);

private:
    EventCallback read_callback_ = []{};
    EventCallback write_callback_ = []{};
    EventCallback close_callback_ = []{};
    EventCallback error_callback_ = []{};
    int sockfd_ = 0;
    int events_ = 0;
};

using ChannelPtr = std::shared_ptr<Channel>;

#endif //CHANNEL_H
